﻿using Caliburn.Micro;
using LiveCharts;
using LiveCharts.Wpf;
using SD.Infrastructure.DTOBase;
using SD.Infrastructure.WPF.Caliburn.Aspects;
using SD.Infrastructure.WPF.Caliburn.Base;
using SD.IOC.Core.Mediators;
using SlamDunk.MES.IAppService.DTOs.Outputs.ConfigurationContext;
using SlamDunk.MES.IAppService.Interfaces;
using SlamDunk.MES.Presentation;
using SlamDunk.MES.ReportView.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.ServiceModel.Extensions;
using System.Threading;
using System.Threading.Tasks;

namespace SlamDunk.MES.Client.ViewModels.Home
{
    /// <summary>
    /// 仪表盘视图模型
    /// </summary>
    public class DashboardViewModel : ScreenBase
    {
        #region # 字段及构造器

        /// <summary>
        /// 配置管理服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IConfigurationContract> _configurationContract;

        /// <summary>
        /// 报表统计服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IReportContract> _reportContract;

        /// <summary>
        /// 窗口管理器
        /// </summary>
        private readonly IWindowManager _windowManager;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public DashboardViewModel(ServiceProxy<IConfigurationContract> configurationContract, ServiceProxy<IReportContract> reportContract, IWindowManager windowManager)
        {
            this._configurationContract = configurationContract;
            this._reportContract = reportContract;
            this._windowManager = windowManager;
        }

        #endregion

        #region # 属性

        #region 物料投入下拉列表 —— ObservableCollection<MaterialQuantityInfo> MaterialIns
        /// <summary>
        /// 物料投入下拉列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<MaterialQuantityInfo> MaterialIns { get; set; }
        #endregion

        #region 已选物料投入下拉列表 —— MaterialQuantityInfo SelectedMaterialIn
        /// <summary>
        /// 已选物料投入下拉列表
        /// </summary>
        [DependencyProperty]
        public MaterialQuantityInfo SelectedMaterialIn { get; set; }
        #endregion

        #region  产品产出下拉列表 —— ObservableCollection<ProductQuantityInfo> ProductOuts
        /// <summary>
        /// 产品产出下拉列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<ProductQuantityInfo> ProductOuts { get; set; }
        #endregion

        #region 已选产品产出下拉列表 —— ProductQuantityInfo SelectedProductOut
        /// <summary>
        /// 已选产品产出下拉列表
        /// </summary>
        [DependencyProperty]
        public ProductQuantityInfo SelectedProductOut { get; set; }
        #endregion

        #region 工作通知列表 —— ObservableCollection<NotificationInfo> Notifications
        /// <summary>
        /// 工作通知列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<NotificationInfo> Notifications { get; set; }
        #endregion

        #region 使用指南文本 —— string UseGuideText
        /// <summary>
        /// 使用指南文本
        /// </summary>
        [DependencyProperty]
        public string UseGuideText { get; set; }
        #endregion

        #region 良品率饼图 —— SeriesCollection SeriesCollection
        /// <summary>
        /// 良品率饼图
        /// </summary>
        [DependencyProperty]
        public SeriesCollection SeriesCollection { get; set; }
        #endregion

        #region 物料投入折线图 —— SeriesCollection SeriesCollectionIn
        /// <summary>
        /// 物料投入折线图
        /// </summary>
        [DependencyProperty]
        public SeriesCollection SeriesCollectionIn { get; set; }

        [DependencyProperty]
        public string[] LabelIns { get; set; }
        #endregion

        #region 产品产出折线图 —— SeriesCollection SeriesCollectionOut
        /// <summary>
        /// 产品产出折线图
        /// </summary>
        [DependencyProperty]
        public SeriesCollection SeriesCollectionOut { get; set; }

        [DependencyProperty]
        public string[] LabelOuts { get; set; }
        #endregion

        #endregion

        #region # 方法

        //Initializations

        #region 初始化 —— override Task OnInitializeAsync(CancellationToken cancellationToken)
        /// <summary>
        /// 初始化
        /// </summary>
        protected override async Task OnInitializeAsync(CancellationToken cancellationToken)
        {
            await this.Load();
        }
        #endregion

        #region 加载 —— async Task Load()
        /// <summary>
        /// 加载
        /// </summary>
        public async Task Load()
        {
            this.MaterialIns = new ObservableCollection<MaterialQuantityInfo>();
            this.ProductOuts = new ObservableCollection<ProductQuantityInfo>();
            PageModel<NotificationInfo> pageModel = await Task.Run(() => this._configurationContract.Channel.GetNotificationsByPage(null, null, null, null, 1, 10));
            this.Notifications = new ObservableCollection<NotificationInfo>(pageModel.Datas);
            this.UseGuideText = ConfigurationManager.AppSettings[Constants.UseGuideKey];

            await this.ReloadNotifications();
            await this.ReloadMaterialQuantityIn();
            await this.ReloadProductQuantityOut();
        }
        #endregion


        //Actions

        #region 查看使用指南 —— async void LookManual()
        /// <summary>
        /// 查看使用指南
        /// </summary>
        public async void LookManual()
        {
            ManualViewModel viewModel = ResolveMediator.Resolve<ManualViewModel>();
            viewModel.Load();
            await this._windowManager.ShowDialogAsync(viewModel);
        }
        #endregion

        #region 查看工作通知 —— async void LookNotification(NotificationInfo notificationInfo)
        /// <summary>
        /// 查看工作通知
        /// </summary>
        public async void LookNotification(NotificationInfo notificationInfo)
        {
            LookNotificationViewModel viewModel = ResolveMediator.Resolve<LookNotificationViewModel>();
            viewModel.Load(notificationInfo);
            await this._windowManager.ShowDialogAsync(viewModel);
        }
        #endregion

        #region 物料投入下拉列表事件 —— async void LoadMaterialIn()
        /// <summary>
        /// 物料投入下拉列表事件
        /// </summary>
        public async void LoadMaterialIn()
        {
            await this.ReloadMaterialQuantityIn();
        }
        #endregion

        #region 产品产出下拉列表事件 —— async void LoadProductOut()
        /// <summary>
        /// 产品产出下拉列表事件
        /// </summary>
        public async void LoadProductOut()
        {
            await this.ReloadProductQuantityOut();
        }
        #endregion


        //Private

        #region 加载良品率饼图 —— async Task ReloadNotifications()
        /// <summary>
        /// 加载良品率饼图
        /// </summary>
        private async Task ReloadNotifications()
        {
            //TODO 饼图重构
            //IDictionary<MaterialInfo, decimal> materials = await Task.Run(() => _iReportContract.Channel.GetProductQualifiedRates(DateTime.Today));
            //this.SeriesCollection = new SeriesCollection();
            //foreach (var material in materials)
            //{
            //    PieSeries pieSeries = new PieSeries
            //    {
            //        Title = material.Key.Name,
            //        Values = new ChartValues<decimal> { material.Value }
            //    };
            //    this.SeriesCollection.Add(pieSeries);
            //}
        }
        #endregion

        #region 加载物料投入 —— async Task ReloadMaterialQuantityIn()
        /// <summary>
        /// 加载物料投入
        /// </summary>
        private async Task ReloadMaterialQuantityIn()
        {
            IDictionary<DateTime, MaterialQuantityInfo[]> materialQuantitys = await Task.Run(() => this._reportContract.Channel.GetMaterialInputPeriodicSummaries(DateTime.Today.AddDays(-7), DateTime.Today));
            this.SeriesCollectionIn = new SeriesCollection();
            List<string> labelIns = new List<string>();
            List<LineSeriesInfo> lineSeriesList = new List<LineSeriesInfo>();
            foreach (KeyValuePair<DateTime, MaterialQuantityInfo[]> materialQuantity in materialQuantitys)
            {
                foreach (MaterialQuantityInfo material in materialQuantity.Value)
                {
                    LineSeriesInfo lineSeries = lineSeriesList.SingleOrDefault(x => x.MaterialName == material.MaterialName);
                    if (lineSeries == null)
                    {
                        if (this.MaterialIns.All(x => x.MaterialId != material.MaterialId))
                        {
                            this.MaterialIns.Add(material);
                        }
                        LineSeriesInfo lineSeriesInfo = new LineSeriesInfo
                        {
                            MaterialName = material.MaterialName,
                            Quantitys = new ChartValues<decimal> { material.Quantity }
                        };
                        lineSeriesList.Add(lineSeriesInfo);
                    }
                    else
                    {
                        int index = lineSeriesList.IndexOf(lineSeries);
                        lineSeriesList.Remove(lineSeries);
                        lineSeries.Quantitys.Add(material.Quantity);
                        lineSeriesList.Insert(index, lineSeries);
                    }
                }
                labelIns.Add(materialQuantity.Key.ToString("yyyy-MM-dd"));
            }
            if (this.SelectedMaterialIn != null)
            {
                lineSeriesList = lineSeriesList.Where(x => x.MaterialName == this.SelectedMaterialIn.MaterialName).ToList();
            }
            foreach (LineSeriesInfo lineSeriesInfo in lineSeriesList)
            {
                LineSeries lineSeries = new LineSeries
                {
                    Title = lineSeriesInfo.MaterialName,
                    Values = lineSeriesInfo.Quantitys
                };
                this.SeriesCollectionIn.Add(lineSeries);
            }

            this.LabelIns = labelIns.ToArray();
        }
        #endregion

        #region 加载产品产出 —— async Task ReloadProductQuantityOut()
        /// <summary>
        /// 加载产品产出
        /// </summary>
        private async Task ReloadProductQuantityOut()
        {
            IDictionary<DateTime, ProductQuantityInfo[]> productQuantitys = await Task.Run(() => this._reportContract.Channel.GetProductOutputPeriodicSummaries(DateTime.Today.AddDays(-7), DateTime.Today));
            this.SeriesCollectionOut = new SeriesCollection();
            List<string> labelOuts = new List<string>();
            List<LineSeriesInfo> lineSeriesList = new List<LineSeriesInfo>();
            foreach (KeyValuePair<DateTime, ProductQuantityInfo[]> productQuantity in productQuantitys)
            {
                foreach (ProductQuantityInfo product in productQuantity.Value)
                {
                    if (this.SelectedProductOut == null)
                    {
                        this.SelectedProductOut = product;
                    }
                    if (this.ProductOuts.All(x => x.ProductId != product.ProductId))
                    {
                        this.ProductOuts.Add(product);
                    }
                    if (this.SelectedProductOut.ProductId == product.ProductId)
                    {
                        LineSeriesInfo lineSeries = lineSeriesList.SingleOrDefault(x => x.MaterialName == product.ProductName);
                        if (lineSeries == null)
                        {
                            LineSeriesInfo lineSeriesInfo = new LineSeriesInfo
                            {
                                MaterialName = product.ProductName,
                                Quantitys = new ChartValues<decimal> { product.ExpGrossQuantity }
                            };
                            lineSeriesList.Add(lineSeriesInfo);
                        }
                        else
                        {
                            int index = lineSeriesList.IndexOf(lineSeries);
                            lineSeriesList.Remove(lineSeries);
                            lineSeries.Quantitys.Add(product.ExpGrossQuantity);
                            lineSeriesList.Insert(index, lineSeries);
                        }
                    }
                }
                labelOuts.Add(productQuantity.Key.ToString("yyyy-MM-dd"));
            }
            foreach (LineSeriesInfo lineSeriesInfo in lineSeriesList)
            {
                LineSeries lineSeries = new LineSeries
                {
                    Title = lineSeriesInfo.MaterialName,
                    Values = lineSeriesInfo.Quantitys
                };
                this.SeriesCollectionOut.Add(lineSeries);
            }

            this.LabelOuts = labelOuts.ToArray();
        }
        #endregion

        #endregion
    }


    /// <summary>
    /// 折线图模型
    /// </summary>
    public class LineSeriesInfo
    {
        public string MaterialName { get; set; }
        public ChartValues<decimal> Quantitys { get; set; }
    }
}
